package com.example.hello.views.organizations;

import com.example.hello.*;
import com.example.hello.POJO.OrganizationPOJO;
import com.example.hello.POJO.TrackPOJO;
import com.example.hello.POJO.UserPOJO;
import com.example.hello.views.Wireframe1;
import com.example.hello.views.tracks.Tracks;
import com.example.hello.views.users.Users;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.VerticalLayout;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.ObjectWriter;
import org.codehaus.jackson.type.TypeReference;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class Organizations extends VerticalLayout implements View {

    public static final String NAME = "organizations";

    private static UserPOJO currentUser;
    private static Set<OrganizationPOJO> orgs = new HashSet<>();

    private VerticalLayout addLayout = new VerticalLayout();
    private VerticalLayout viewLayout = new VerticalLayout();

    private HorizontalLayout add = new HorizontalLayout();
    private BootstrapButton view = new BootstrapButton("View", BootstrapButton.Size.SMALL);
    private BootstrapButton delete = new BootstrapButton("Delete", BootstrapButton.Size.SMALL);

    private StringWrap selectedOrg;

    @Override
    public void enter(ViewChangeListener.ViewChangeEvent event) {
        currentUser = ((HelloUI) HelloUI.getCurrent()).getUser();
        if (currentUser == null) currentUser = new UserPOJO();
//        orgs = GETOrganizations("");
//        if (orgs == null) orgs = new HashSet<>();

        add.setVisible(currentUser.isSiteAdmin());
        delete.setVisible(currentUser.isSiteAdmin());
        if (currentUser.isSiteAdmin()) {
            view.setWidth("110px");
        } else {
            view.setWidth("220px");
        }

        /** Redirect to Organization View if needed **/
        String[] parameters = event.getParameters().split("/");
        if (!parameters[0].equals("")) {
            OrganizationPOJO org = Organization.GETOrg(parameters[0]);
            if (org != null) {
                Organization orgView = new Organization(Organizations.NAME + "/" + org.getEncodedName(), org);
                getUI().getNavigator().addView(orgView.NAME, orgView);
                getUI().getNavigator().navigateTo(orgView.NAME);
            } else {
                getUI().getNavigator().navigateTo(NAME);
            }
        }
    }

    public Organizations() {
        setWidth("100%");
        selectedOrg = new StringWrap();

        currentUser = ((HelloUI) HelloUI.getCurrent()).getUser();
        if (currentUser == null) currentUser = new UserPOJO();
        orgs = GETOrganizations("");
        if (orgs == null) orgs = new HashSet<>();

        initAdd();
        initDisplay();

        addComponents(addLayout, viewLayout);
        setComponentAlignment(viewLayout, Alignment.TOP_CENTER);
        setExpandRatio(viewLayout, 1);
    }

    private void initAdd() {
        add.setWidth("800px");

        final Heading nameHeading = new Heading("Name", 6);
        final TextField nameField = new TextField();
        final Heading adminsHeading = new Heading("Admins", 6);
        final TextField adminsField = new TextField();
        final BootstrapButton orgSubmit = new BootstrapButton("Add Org");
        orgSubmit.setWidth("120px");

        orgSubmit.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                addOrg(new OrganizationPOJO(nameField.getEncodedValue()));
                getUI().getNavigator().navigateTo(Organizations.NAME);
            }
        });
        TextField.enterKeyHandler(orgSubmit, nameField);

        add.addComponents(
                nameHeading, new HSpacer(5), nameField,
                new HSpacer(20),
                adminsHeading, new HSpacer(5), adminsField,
                new HSpacer(20),
                orgSubmit
        );

        add.setComponentAlignment(nameHeading, Alignment.MIDDLE_LEFT);
        add.setComponentAlignment(nameField, Alignment.MIDDLE_LEFT);
        add.setComponentAlignment(adminsHeading, Alignment.MIDDLE_LEFT);
        add.setComponentAlignment(adminsField, Alignment.MIDDLE_LEFT);
        add.setExpandRatio(nameField, 1);
        add.setExpandRatio(adminsField, 1);

        addLayout.addComponents(new VSpacer(10), add, new VSpacer(20));
        addLayout.setComponentAlignment(add, Alignment.MIDDLE_CENTER);
        addLayout.setExpandRatio(add, 1);
    }

    private void initDisplay() {
        final ListBox orgList = new ListBox();
        delete.setWidth("110px");

        orgList.setVisibleItems(16);
        for (OrganizationPOJO org : orgs) orgList.addItem(org.getDecodedName());
        Collections.sort(orgList.getItems());
        if (orgList.getItems().size() != 0) {
            selectedOrg.setString(orgList.getItems().get(0));
        } else {
            view.setEnabled(false);
            delete.setEnabled(false);
        }
        orgList.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                if (event instanceof ListBoxChangeEvent)
                    selectedOrg.setString(((ListBoxChangeEvent) event).getSelected());
            }
        });
        view.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                getUI().getNavigator().navigateTo(NAME + "/" + selectedOrg.getEncoded());
            }
        });
        delete.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                removeOrg(Organization.GETOrg(selectedOrg.getEncoded()));
                getUI().getNavigator().navigateTo(NAME);
            }
        });

        HorizontalLayout buttons = new HorizontalLayout(view, delete);

        // add organizationList for display
        viewLayout.addComponents(orgList, buttons);
        viewLayout.setComponentAlignment(orgList, Alignment.TOP_CENTER);
        viewLayout.setComponentAlignment(buttons, Alignment.TOP_CENTER);
    }

    public static Set<OrganizationPOJO> GETOrganizations(String query) {
        Set<OrganizationPOJO> orgs = new HashSet<>();
        try {
            String json = HttpRequest.GET(Organizations.NAME + query);
            ObjectMapper mapper = new ObjectMapper();
            orgs = mapper.readValue(json, new TypeReference<Set<OrganizationPOJO>>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return orgs;
    }

    public static Set<OrganizationPOJO> getOrganizations() {
        return orgs;
    }

    public static void setOrganizations(Set<OrganizationPOJO> orgs) {
        Organizations.orgs = orgs;
    }

    public static boolean addOrg(OrganizationPOJO org) {
        // post an org to get an _id
        if (!HttpRequest.executePost(NAME, org.toJSON())) return false;

        // get the org with _id attached
        org = Organization.GETOrg(org.getEncodedName());
        if (!orgs.contains(org)) orgs.add(org);

        // create the View with the org
        Organization orgView = new Organization(Organizations.NAME + "/" + org.getEncodedName(), org);
        HelloUI.getCurrent().getNavigator().addView(orgView.NAME, orgView);

        return true;
    }

    public static boolean removeOrg(OrganizationPOJO org) {
        // get all linked resources and update or relocate
        Set<TrackPOJO> tracks = Tracks.GETTracks("?org=" + org.getEncodedName());
        Set<UserPOJO> admins = Users.GETUsers("?assignedOrg=" + org.getEncodedName());
        Set<UserPOJO> users = Users.GETUsers("?org=" + org.getEncodedName());
        for (TrackPOJO track : tracks) {
            track.setOrganization(TrackPOJO.UNASSIGNED);
            track.update();
        }
        for (UserPOJO admin : admins) {
            if (admin.removeAssignedOrg(org.getEncodedName())) admin.update();
        }
        for (UserPOJO user : users) {
            if (user.removeOrg(org.getEncodedName())) user.update();
        }

        // delete the org
        HttpRequest.executeDelete(NAME + "/" + org.getEncodedName());
        HelloUI.getCurrent().getNavigator().removeView(NAME + "/" + org.getEncodedName());

        return orgs.remove(org);
    }

    public static boolean hasOrg(OrganizationPOJO org) {
        return orgs.contains(org);
    }

}